package com.nx.platform.es.common.utils;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author
 * @since Aug 12, 2015
 */
public class MoreThreadFactorys {

    /**
     * @param threadNamePrefix
     * @return
     */
    public static ThreadFactory newNameableDaemonThreadFactory(String threadNamePrefix) {
        return new NameableThreadFactory(true, threadNamePrefix);
    }

    /**
     * @param threadNamePrefix
     * @return
     */
    public static ThreadFactory newNameableThreadFactory(String threadNamePrefix) {
        return new NameableThreadFactory(false, threadNamePrefix);
    }

    /**
     * @param name
     * @return
     */
    public static ThreadFactory newSingleThreadNameableDaemonThreadFactory(String name) {
        return new SingleThreadNamebleThreadFactory(true, name);
    }

    /**
     * @param name
     * @return
     */
    public static ThreadFactory newSingleThreadNameableThreadFactory(String name) {
        return new SingleThreadNamebleThreadFactory(false, name);
    }

    private static class SingleThreadNamebleThreadFactory implements ThreadFactory {

        private final ThreadGroup group;
        private final String name;
        private final boolean daemon;

        public SingleThreadNamebleThreadFactory(boolean daemon, String name) {
            this.daemon = daemon;
            SecurityManager s = System.getSecurityManager();
            this.group = (s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup());
            this.name = name;
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(this.group, r, name, 0L);
            if (daemon) {
                if (!t.isDaemon()) {
                    t.setDaemon(true);
                }
            } else {
                if (t.isDaemon()) {
                    t.setDaemon(false);
                }
            }
            if (t.getPriority() != 5) {
                t.setPriority(5);
            }
            return t;
        }

    }

    private static class NameableThreadFactory implements ThreadFactory {

        private static final ConcurrentMap<String, AtomicInteger> nameMap = new ConcurrentHashMap<String, AtomicInteger>();

        private final ThreadGroup group;
        private final String namePrefix;
        private final boolean daemon;

        public NameableThreadFactory(boolean daemon, String namePrefix) {
            this.daemon = daemon;
            SecurityManager s = System.getSecurityManager();
            this.group = (s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup());
            this.namePrefix = namePrefix;
            nameMap.putIfAbsent(this.namePrefix, new AtomicInteger(0));
        }

        public Thread newThread(Runnable r) {
            String name = (namePrefix + "-" + nameMap.get(namePrefix).incrementAndGet());
            Thread t = new Thread(this.group, r, name, 0L);
            if (daemon) {
                if (!t.isDaemon()) {
                    t.setDaemon(true);
                }
            } else {
                if (t.isDaemon()) {
                    t.setDaemon(false);
                }
            }
            if (t.getPriority() != 5) {
                t.setPriority(5);
            }
            return t;
        }
    }

}
